home *** CD-ROM | disk | FTP | other *** search
/ Belgian Amiga Club - ADF Collection / BS1 part 34.zip / BS1 part 34 / FredFish PD 307.adf / Samp / SAMPlib.doc < prev    next >
Text File  |  1990-01-13  |  19KB  |  395 lines

  1.     This is the document for the dissidents' samp.library 1.0 © 1989. Set your
  2. editor's TAB width to 3.
  3.  
  4.  
  5.                 «««««««««««««« WHAT THE HELL IS SAMP? »»»»»»»»»»»»
  6.     (or "If it doesn't have anything to do with video, what good is it?")
  7.  
  8.     The dissidents' samp.library is a library used to load and save SAMP files.
  9. SAMP is an IFF file format used to store any resolution audio data. This format
  10. is used in dissidents' Midi Sample Wrench, a 16 bit audio waveform editing
  11. program for the Amiga, and is currently under consideration for adoption by
  12. CATS. The samp.library will allow you to write applications that can save
  13. and retrieve audio data saved in the SAMP format. For a detailed spec of the
  14. SAMP format, consult the SAMP.doc file.
  15.     The samp.library is written entirely in 68000 assembly for speed and small
  16. size. Distributed with the library are C and assembly Include files and example
  17. applications, as well as a utility to convert 8SVX files to SAMP.
  18.  
  19.  
  20.                 ««««««««««««««««« COPYRIGHT NOTICE »»»»»»»»»»»»»»»»»»
  21.  
  22.     The samp.library and ToSAMP conversion utility are copyright by dissidents
  23. software. These two files may be used by and freely distributed with any
  24. application, commercial or otherwise, although copyright is retained exclu-
  25. sively by dissidents, and the files must not be modified in any way. In
  26. addition, the following files are copyright by dissidents, and may only be
  27. distributed on disks which are freely-distributable or for which a nominal
  28. charge to cover media and shipping is the only consumer cost:
  29.  
  30.     1). SAMPlib.doc
  31.     2). SAMP.doc
  32.     3). ToSAMP.asm
  33.     4). Exam.c
  34.     5). Exam.asm
  35.     6). SAMP.i
  36.     7). SAMP.h
  37.     8). SAMPInterface.asm
  38.  
  39.     All copyright notices must remain intact.
  40.  
  41.  
  42.                 «««««««««««««««« CURRENT LIMITATIONS »»»»»»»»»»»»»»»»
  43.  
  44.     The library does not support loading/saving SAMP files inside of a CAT or
  45. LIST, nor does it currently support Continuation files or NumOfChans > 4.
  46.     Due to memory considerations, the library can only be servicing one task
  47. at any given moment (though several tasks may simultaneously open the library).
  48.  
  49.  
  50.                 ««««««««««««««««« DATA STRUCTURES »»»»»»»»»»»»»»»»»
  51.  
  52.     Before you open and use the samp.library, you must create a few structures
  53. and variables from which the library can load/save data. The most important
  54. structure is is the SampleHeader64 structure. It is used to hold information
  55. about 1 waveform such as its size, OneShotStart and LoopStart addresses, Root
  56. Note, and velocity table. Each waveform that is loaded must have its own 64
  57. byte SampleHeader64 structure. Furthermore, all the SampleHeader64 structures
  58. must be contiguous in memory. For this reason, an application should allocate
  59. the proper number of SampleHeader64 structures before actually loading the
  60. waveform data. This can be done by either of the following procedures:
  61.  
  62.     1).    Determine the maximum # of waves that the application can load, and
  63.             declare an array of this many SampleHeader64 structures.
  64.             (The C example takes this approach).
  65.  
  66.     2).    After opening a file (via OpenSampRead) and examining the MHDR's
  67.             NumOfWaves, allocate a block of mem with size = sizeofSampleHeader64
  68.             * NumOfWaves.
  69.  
  70.     The string buffers for the waves' names must also be contiguous in memory.
  71. For this reason, your application must decide upon the maximum length of each
  72. name, and allocate an appropriately sized mem block. On the other hand, you
  73. may forego allocating any string buffers, in which case the library will ignore
  74. loading the waves' names.
  75.  
  76.     Finally, a pointer to a TransposeNode must be declared (and initially set
  77. to zero).  A TransposeNode is a structure that the library will create for
  78. every different sampleRate in a SAMP file. These structures are all linked
  79. into a list to which your variable points. A TransposeNode contains a transpose
  80. table as described in the SAMP doc.
  81.  
  82.  
  83.             «««««««««««««««««« LIBRARY STRUCTURES »»»»»»»»»»»»»»»»
  84.  
  85.     When you open a SAMP file to read or write, you gain exclusive access to
  86. the samp.library's structures until you close the file. One structure is a
  87. SAMPInfo structure. This contains an imbedded MHDR chunk. When you open a
  88. SAMP for reading via OpenSampRead(), the SAMP's MHDR is loaded into the library
  89. SAMPInfo's MHDR.  So, you can examine the file's NumOfWaves, NumOfChans,
  90. Format, etc before loading any wave data. The SAMPInfo also contains fields to
  91. store pointers to (addresses of) functions within your application. These
  92. functions will be called at certain times by the library's read/write routines.
  93. For example, you can supply a pointer to a function which will be called by
  94. the library's ReadWaves() for every wave's FATK data handling. The SAMPInfo
  95. also contains fields to specify the maximum allowed length of a wave's name,
  96. the type of mem into which the wave data will be loaded, and Seek() offsets
  97. from the beginning of the file to various chunks.
  98.  
  99.     The library also has a waveHeader structure as described in the SAMP doc.
  100. This structure is used by ReadWaves() and WriteWaves() to hold data per each
  101. wave read/written.
  102.  
  103.  
  104.         «««««««««««««««««««« OPENING THE LIBRARY »»»»»»»»»»»»»»»»»»»
  105.  
  106.     The samp.library file must be copied to the libs drawer of your boot disk.
  107.  
  108. Then, any application may open and use the library via a call to Exec's
  109. OpenLibrary(). The current version of samp is 0. The library is closed via
  110. Exec's CloseLibrary().  C applications must be linked with the module
  111.  
  112.                             SAMPInterface.asm
  113.  
  114. (which itself must be assembled by your C compiler's assembler).
  115.  
  116.  
  117.         ««««««««««««««««««««« THE LIBRARY FUNCTIONS »»»»»»»»»»»»»»»»»»
  118.  
  119.     Here are descriptions and calling procedures for the library functions:
  120.  
  121.  
  122. *************************** OpenSampRead *****************************
  123.  
  124.     This routine must be called first in order to read in a SAMP file and
  125.  perform operations on it via other library routines such as LoadNames,
  126.  LoadPlaymap, MixPlaymap, and ReadWaves. It opens the file, determines
  127.  if it is a SAMP file that the library can read, and prevents other tasks
  128.  from using the library until the file is processed and closed.
  129.  
  130.     This is passed the name of the SAMP file to be opened (a NULL-terminated
  131.  string). Also, you may pass a pointer to a function which the library should
  132.  call for unknown chunks, or instead pass in 0. The library understands
  133.  "BODY", "AUTH", "ANNO", "NAME", "MHDR" and "(c) " chunks. If you pass a 0,
  134.  it will ignore all other chunks. If you pass a pointer to your own function,
  135.  it will call your function as so:
  136.  
  137.  flag = UnknownChunk(SAMPInfo, SeekOffset, ChunkSize ID);
  138.                             a4                d4                    d2        d0
  139.  
  140.  If you return a 1, then the OpenSampRead terminates and closes the file.
  141.  A 0 allows OpenSampRead to continue.
  142.  For more details, see the section "PROCESSING UNKNOWN CHUNKS".
  143.  
  144.  OpenSampRead() returns the address of the library's SAMPInfo structure
  145.  or 0 if an error. The z-flag is cleared for error (bne Error), set otherwise.
  146.  An error may be caused by some other task already using the library, failure
  147.  to open the requested file, the requested file is not a SAMP file, or the BODY
  148.  for this SAMP file cannot be located within this file (i.e. will not support
  149.  Continuation files). For C programmers, the exact error number is returned
  150.  in a variable called SAMPError (which is a global in the module
  151.  SampInterface.asm). For assembly programmers, the exact error number is
  152.  returned in d1.
  153.  
  154.     SAMPInfo = OpenSampRead( Filename, UnKnownVector );
  155.         d0                                d1                    a0
  156.  
  157.  
  158. ***************************** CloseSamp *******************************
  159.  
  160.   Closes a SAMP file that was opened for reading or writing, and frees the
  161. library for other tasks to use. This must be called after you have successfully
  162. opened a SAMP file (via OpenSampRead or OpenSampWrite), and are finished
  163. processing it.
  164.  
  165.     CloseSamp();
  166.  
  167.  
  168. ***************************** ReadWaves *********************************
  169.  
  170. #define nameSize 20
  171.  
  172.  total = ReadWaves(offsetWave,totalWaves,nameBuffer[offsetWave][nameSize],SampleHeader64[offsetWave]);
  173.     d0                            d6            d7                    a2                                    a3
  174.  
  175.      Loads the specified range of waves within the SAMP file between offsetWave
  176.  and offsetWave+totalWaves. offsetWave is the first wave to start loading
  177.  (with the first wave in the SAMP file being wave #0). Loads them starting at
  178.  the passed SampleHeader64. Also loads the names for these waves starting at
  179.  nameBuffer unless passed a NULL. Before calling ReadWaves, you should
  180.  set the library SAMPInfo's MaxChars variable to the max # of chars each
  181.  nameBuffer can hold. The default is 20 bytes. All names are padded out with
  182.  spaces and NULL-terminated.
  183.  
  184.      Also, you should set the SAMPInfo's ATAKvector, RLSEvector, FATKvector,
  185.  FRLSvector, USERvector, and EXTRAvector to point to any routines you want the
  186.  library to call per wave. If you don't, the default is for the library to
  187.  ignore FATK, FRLS, and USER data, and to read/reformat ATAK and RLSE EGPoints
  188.  into the SampleHeader64's envelope fields.
  189.  
  190.  offsetWave is specified from zero (i.e. a value of zero won't skip any waves
  191.  in the file. A 2 will skip the first 2 waves in the file and start loading the
  192.  3rd wave into SampleHeader1.) For totalWaves = 1, only 1 wave is loaded.
  193.  
  194.      This returns the number of waves actually loaded (0 if none). Sets
  195.  z-flag for success, cleared for error. For C programmers, the exact error
  196.  number is returned in a variable called SAMPError. For assembly programmers,
  197.  the exact error number is returned in d1.
  198.  
  199.     Each wave's SampleHeader64 structure has an TransTable field. ReadWaves()
  200.  places each wave's sampleRate in this field. Later, you can extract the value
  201.  from this field when making the transpose tables, and rewrite the field with
  202.  a pointer to the ORIGINAL pitch of the table. See the C example.
  203.  
  204.     The library calls your ATAK, RLSE, FATK, FRLS, or USER vector only if a
  205.  wave has data. In other words, if a wave doesn't have any FRLS EGPoints,
  206.  then the library skips calling your FRLS vector when loading that wave.
  207.  The library calls your EXTRA vector AFTER each wave's 80 byte waveHeader
  208.  and sample data are read in. This vector is useful for getting the library
  209.  waveHeader's midiSampNum, loopType, and instrumType if you wish to use/store
  210.  this data.
  211.     Your vectors are passed the lib's SAMPInfo and waveHeader, the current
  212.  SampleHeader64 address (a pointer to a SampleHeader64), and waveNumber
  213.  (minus offsetWave).
  214.     They should return an abort flag (1 = Abort read, 0 = continue). For
  215.  example, the library calls your FATK routine as so:
  216.  
  217.  flag = FATKroutine(waveHeader, SAMPInfo, SampleHeader, waveNumber);
  218.     d0                            a5                a4                a3                d5
  219.  
  220.     When reading a SAMP, you should either read or seek past any data from
  221.  within an ATAK, RLSE, FATK, FRLS, or USER vector. When the library calls your
  222.  ATAK, RLSE, FATK, FRLS, or USER vector, the DOS file position will be at the
  223.  expected data within the SAMP file. In other words, when the library calls
  224.  your FATK vector, the file position will be at the wave's FATK data (if there
  225.  is any). When the library calls your USER vector, the file position will be
  226.  at the wave's USER data (if any). The library passes your vector the size of
  227.  the data (in bytes). Your vector must either read exactly this many bytes of
  228.  data, or Seek() forward this many bytes from the current position. In other
  229.  words, when your vector returns, the new file position must be at the next
  230.  byte AFTER the expected data. If you Seek() somewhere else in the file, always
  231.  Seek() back to the point after the expected data before your vector returns. 
  232.  
  233.  
  234. *************************** LoadPlayMap ********************************
  235.     Checks each byte of the loaded PlayMap. For every wave number above or below
  236.  the wave range (offsetWave+1 to offsetWave+totalWaves) in the loaded PlayMap,
  237.  the application's destination PlayMap byte is left as is. Otherwise, the wave
  238.  number is set to
  239.  
  240.     (SAMPInfo's NumOfWaves - offsetWave) + startWave
  241.  
  242.  where startWave is the number of the SampleHeader where the first wave
  243.  was loaded in. (startWave and offsetWave both referenced from wave #0)
  244.  numOfChans is the # of channels for each midi note in the destination playMap.
  245.  LoadPlaymap simply zeros out the destination playMap first.
  246.      If totalWaves = 0, LoadPlaymap just zeros out the playMap and MixPlaymap
  247.  does nothing. In this case, offsetWave and startWave are ignored.
  248.  
  249.  MixPlayMap(totalWaves,numOfChans,offsetWave,startWave,destPlayMap);
  250.                     d0            d1                d6            d7                a0
  251.  
  252.  
  253. *************************** MakeTransTable ***************************
  254.     Makes a TransposeNode for the passed sampleRate (in hz). The transpose table
  255.  will have the specified # of steps above and below the ORIGINAL_PITCH as
  256.  described by the upperRange and lowerRange values. This routine will
  257.  allocate and link the TransposeNode into the passed TList only if there
  258.  is not already a table for this sampleRate. Otherwise, returns ORIGPITCH
  259.  of the other table in order to avoid duplication. Returns a zero if not
  260.  enough mem to create a new table, or the passed sampleRate = 0.
  261.  TList holds the address of the first TransposeNode.
  262.  
  263.     You may set the library's SAMPInfo's LowLimit and HighLimit fields
  264.  before calling this. Defaults are 500 and 127 respectively. These are the
  265.  limits between which the period values must range within the Transpose table.
  266.  If a period is outside these limits, then the Transpose table entry is set
  267.  to zero to indicate that the period is out of range. When playing back the
  268.  wave, it is then easy to determine if a certain transposition of a wave's
  269.  sample Rate results in a period out of range. The default limits are set for
  270.  normal DMA audio and should not be altered unless your program does non-DMA
  271.  audio output.
  272.  
  273.  ORIGPITCHaddress = MakeTransTable(sampleRate,upperRange,lowerRange,&TList);
  274.         d0                                            d5                d6            d7            a2
  275.  
  276.  
  277. ***************************** OpenSampWrite ***************************
  278.  Opens the SAMP filename for writing. Must be called before using WriteMHDR,
  279.  WriteName, WriteChunk, or WriteWaves. Returns the address of the library's
  280.  SAMPInfo if success, or a zero if the file couldn't be created. Upon
  281.  successful return, application should set SAMPInfo's Format, PlayMode,
  282.  NumWaves, and NumOfChans. The defaults for these are 8 bit, INDEPENDENT,
  283.  0 waves, and 4 channels. z-flag cleared for error.
  284.  
  285.  SAMPInfo=OpenSampWrite(fileName);
  286.     d0                                d1
  287.  
  288.  
  289. ******************************* WriteMHDR ******************************
  290.  Writes out the SAMP and MHDR with SAMP header fileSize = 14+sizeOfPlayMap.
  291.  Adjusts your PlayMap bytes so that all wave numbers < startWave and > =
  292.  startWave+numWaves are set to 0. startWave is from 0 being the first wave.
  293.  Returns a 1 if success, 0 if an error.
  294.  
  295.  BOOL WriteMHDR(startWave,playMap);
  296.  d0                    d0            a0
  297.  
  298.  
  299. ******************************* WriteSampChunk ***************************
  300.  Writes out the passed ID, size (of data, not including header), and data.
  301.  Returns a 1 if success, 0 if an error.
  302.  
  303.  BOOL = WriteSampChunk(ID,size,data);
  304.     d0                          d0     d1    a0
  305.  
  306.  
  307. ****************************** WriteSampData ******************************
  308.  Writes out the data for the passed number of bytes and the passed data ptr.
  309.  This is commonly used by vector routines writing out FATK, FRLS, and USER
  310.  data when saving a wave. Returns a 1 if success, 0 if an error.
  311.  
  312.  BOOL = WriteSampData(numOfBytes, dataPtr);
  313.     d0                                d3            a0
  314.  
  315.  
  316. ****************************** WriteNames ********************************
  317.  Writes the NAME chunk. Uses SAMPInfo's NumWaves to determine how many wave
  318.  names to write. Passed the base of the first string buffer. Passed the size
  319.  of a string buffer. Ignores trailing spaces on each name.
  320.  Returns a 1 if success, 0 if an error.
  321.  
  322.  BOOL WriteNames(bufsize, bufPtr);
  323.     d0                    d0            a0
  324.  
  325.  
  326. ******************************* WriteWaves *****************************
  327.  
  328.  BOOL WriteWaves(offsetWave,totalWaves,SampleHeader64[0],TList)
  329.  d0                        d0                d1                a0            a1
  330.  
  331.      Writes the specified range of waves between offsetWave and offsetWave +
  332.  totalWaves to the SAMP file. offsetWave is the first wave to start saving
  333.  (with the first SampleHeader64 being wave #0).
  334.  
  335.     offsetWave is specified from zero (i.e. a value of zero won't skip any
  336.  SampleHeader64 structs. A 2 will skip the first 2 SampleHeader64s and start
  337.  saving the 3rd SampleHeader64 as wave #0.) For totalWaves = 1, only 1 wave
  338.  is saved.
  339.  
  340.     totalWaves is the number of waves to save. If totalWaves = 0, it returns 1
  341.  and writes an "empty" BODY chunk.
  342.  
  343.     TList holds the address of the first TTNode. (a C handle)
  344.  
  345.      Before calling WriteWaves(), you should set the SAMPInfo's ATAKvector,
  346.  RLSEvector, FATKvector, FRLSvector, USERvector, and EXTRAvector to point to
  347.  any routines you want the library to call per wave. If you don't, the default
  348.  is for the library to write no FATK, FRLS, and USER data, and to write ATAK
  349.  and RLSE EGPoints based upon the SampleHeader64's envelope fields.
  350.  
  351.  WriteWaves() calls your EXTRAvector BEFORE the each wave's 80 byte waveHeader
  352.  and data is written out. This vector is useful for setting the library
  353.  waveHeader's SampNum, LoopType, and InsType per wave.
  354.  
  355.  Calls ATAK, RLSE, FATK, FRLS vectors to write out Amplifier/Filter EGPoints,
  356.  and USERvector to write User Data.
  357.  
  358.  The vectors are passed the lib's SAMPInfo and waveHeader, and the current
  359.  SampleHeader. The vectors should return an abort flag (1 = Abort write, 0 =
  360.  continue). For example, the library calls your FATK routine as so:
  361.  
  362.  flag = FATKroutine(waveHeader, SAMPinfo, SampleHeader);
  363.     d0                            a5                a4                a3
  364.  
  365.     You must set the waveHeader's size fields to the number of bytes in the
  366. data written out. For example, if your USER vector writes out 40 bytes of
  367. data, set the waveHeader's USERsize to 40. (You should also set the USERtype).
  368.  
  369.  
  370. ************************** SAMPErrorMsg ****************************
  371.  
  372.  When passed the error number (as returned by OpenSampRead for example),
  373.  this returns the address of a NULL-terminated string describing the error.
  374.  This is suitable for informing the user of any possible errors. For asm
  375.  programmer's certain lib routines return a error number in d1. For C pro-
  376.  grammer's, the error is stored in a variable called SAMPError.
  377.  
  378.  string = SAMPErrorMsg(SAMPError);
  379.     d0                                d1
  380.  
  381.  
  382.             «««««««««««««« PROCESSING UNKNOWN CHUNKS »»»»»»»»»»»»
  383.  
  384.     When your UnknownChunk vector is called by OpenSampRead, it passes a
  385. SeekOffset. This value is the number of bytes from the beginning of the file
  386. to this chunk's ID, and can be used by your application to Seek() to this chunk
  387. later. Your vector should store the chunk ID and SeekOffset for later process-
  388. ing after OpenSampRead returns. The idea is to Seek() to the chunk and process
  389. it, perhaps before or after you ReadWaves(), ReadNames(), LoadPlaymap(),
  390. MixPlaymap(), and certainly before you CloseSamp(). The DOS fileHandle can be
  391. found in the library SAMPInfo's Handle field. Do not do any Seek() or Read()
  392. from within this vector!!! The ChunkSize passed to your vector does not
  393. count the standard, 8 byte IFF chunkID and chunkSize fields that all IFF
  394. chunks must start with.
  395.